package com.wits100.av;

import android.media.MediaCodec;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Surface;

/**
 * Created by chuanjiang.zh on 2016-08-14.
 */
public class JLitePlayer implements LitePlayer, JniMediaReaderListener {

    public static final String TAG = "main";

    public JLitePlayer() {
        mLocalHandler = new LocalHandler();
        mDecodeTask = new DecodeTask();
        mState = MediaType.STATE_STOPPED;
    }


    @Override
    public void setEventListener(EventListener listener) {
        mEventListener = listener;
    }

    @Override
    public void setDisplay(Surface surface) {
        mSurface = surface;

        if (isFormatReady()) {
            if ((mDecodeTask != null) && (mDecodeTask.isOpen())) {
                mDecodeTask.setDisplay(surface);
            } else {
                //
            }
        }

    }

    @Override
    public boolean open(String url) {
        /// 设置连接建立后探测格式的缓冲区大小, 可加快出图
        boolean done = mReader.open(url, "probesize=80240;stimeout=5000000;buffer_size=1024000");
        if (done) {
            mReader.setEventListener(this);
        }
        return done;
    }

    @Override
    public void close() {

        if (mDecodeTask != null) {
            mDecodeTask.close();
        }

        mReader.close();

        mFormat = null;
    }

    @Override
    public boolean isOpen() {

        return mReader.isOpen();
    }

    @Override
    public void play() {
        setState(MediaType.STATE_PLAYING);
        mReader.play();
    }

    @Override
    public void stop() {
        setState(MediaType.STATE_STOPPED);
        mReader.stop();
    }

    @Override
    public boolean snap(String filepath) {
        return false;
    }

    @Override
    public boolean isFormatReady() {
        return (mFormat != null);
    }

    @Override
    public int getState() {
        return mState;
    }


    protected void firePlayEvent(int event, long value) {
        if (mEventListener != null) {
            mEventListener.onPlayEvent(this, event, value);
        }
    }

    protected void onFormatReady() {
        mFormat = mReader.getFormat();

        Log.i(TAG, "format is ready. " + mFormat.toString());

        VideoRender videoRender = new SimpleVideoRender();
        AudioRender audioRender = new SimpleAudioRender();

        mDecodeTask.open(mFormat, mSurface, mReader, videoRender, audioRender);
    }

    protected void setState(int state) {
        this.mState = state;
    }


    protected EventListener mEventListener;
    protected MediaReader mReader = new MediaReader();
    protected LocalHandler mLocalHandler;
    protected DecodeTask mDecodeTask;

    protected Surface mSurface;
    protected MFormat mFormat;
    protected int   mState;


    @Override
    public void onReaderEvent(int handle, int event, long value) {
        Log.i(TAG, "onReaderEvent thread: " + Thread.currentThread().getId());
        Message msg = mLocalHandler.obtainMessage(event, handle);
        msg.getData().putLong("value", value);
        mLocalHandler.sendMessage(msg);
    }

    private void handleReadEvent(int handle, int event, long value) {

        Log.i(TAG, "handleReadEvent thread: " + Thread.currentThread().getId() + " event: " + event);

        int playEvent = event;
        if (event == MediaType.MEDIA_EVENT_OPENING) {
            playEvent = EVENT_OPENING;
        } else if (event == MediaType.MEDIA_EVENT_OPENED) {
            playEvent = EVENT_OPENED;
        } else if (event == MediaType.MEDIA_EVENT_PLAYING) {
            playEvent = EVENT_PLAYING;
        } else if (event == MediaType.MEDIA_EVENT_STOPPED) {
            playEvent = EVENT_STOPPED;
        } else if (event == MediaType.MEDIA_EVENT_END) {
            playEvent = EVENT_END_OF_STREAM;
        } else if (event == MediaType.MEDIA_EVENT_OPEN_FAILED) {
            playEvent = EVENT_ERROR;
        } else if (event == MediaType.MEDIA_EVENT_FORMAT_READY) {
            onFormatReady();
        } else if (event == MediaType.MEDIA_EVENT_PACKET) {
            playEvent = EVENT_BUFFER;
        }

        firePlayEvent(playEvent, value);
    }


    private class LocalHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            int what = msg.what;
            long value = msg.getData().getLong("value");
            handleReadEvent(msg.arg1, what, value);
        }
    }

    private class DecodeTask implements Runnable {

        public DecodeTask() {

        }

        public void open(MFormat fmt, Surface surface, MediaReader reader, VideoRender videoRender, AudioRender audioRender) {
            this.mReader = reader;
            this.videoRender = videoRender;
            this.audioRender = audioRender;

            videoRender.open(fmt, surface);
            audioRender.open(fmt);

            mThread = new Thread(this, "DecoderTask");
            mThread.start();
        }

        public void close() {
            if (mThread != null) {
                mThread.interrupt();
            }

            if (videoRender != null) {
                videoRender.close();
            }
        }

        public boolean isOpen() {
            return (videoRender != null);
        }

        public void setDisplay(Surface surface) {
            if (videoRender != null) {
                videoRender.setDisplay(surface);
            }
        }

        @Override
        public void run() {
            while (!Thread.interrupted()) {
                MPacket pkt = new MPacket();
                int ret = mReader.read(pkt);
                if (ret == 0)
                {
                    if (pkt.length() > 0) {
                        if (pkt.type == MediaType.MEDIA_TYPE_VIDEO) {

                            int flags = 0;
                            if ((pkt.flags & MediaType.AV_PKT_FLAG_KEY) != 0) {
                                flags = MediaCodec.BUFFER_FLAG_KEY_FRAME;
                            }
                            pkt.flags = flags;

                            try {
                                videoRender.input(pkt);
                            } catch (Exception ex) {
                                firePlayEvent(EVENT_ERROR, 0);

                                ex.printStackTrace();
                            }
                        } else {

                            try {
                                audioRender.input(pkt);
                            } catch (Exception ex) {
                                firePlayEvent(EVENT_ERROR, 0);

                                ex.printStackTrace();
                            }
                        }
                    }

                } else if (ret == MediaReader.EAGAIN) {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException ex) {
                        break;
                    }
                } else {
                    Log.w(TAG, "MediaReader return: " + ret);
                }
            }
        }

        protected AudioRender audioRender;
        protected VideoRender videoRender;
        protected MediaReader mReader;
        protected Thread mThread;

    }



}
